package compile

import (
	"fmt"
	"os"
	"strings"
)

func plainError(msg string, exit bool) {
	_, _ = os.Stderr.WriteString("SAIL : " + msg + "\n")

	if exit {
		os.Exit(2)
	}
}

/*
func SyntaxErrorHandler(line, col, offset, partOfSource, errMsg, name, exit)

params:

line: line number
col: col number
offset: offset of this line
partOfSource: Source[line_start : EOL]
errMsg: the reason of error
name: soucename
exit: exit after print error message

*/
type SyntaxErrorHandler func(int, int, int, []byte, string, string, bool)

var ErrExitCode int = 2

func defaultSyntaxErrorHandler(
	line, col int, offset int, partOfSource []byte,
	errMsg string, name string, exit bool) {
	errf := "SyntaxError at (%d : %d) in '%s' : %s:\n\t%s\n\t%s\n"

	// Count offset char length
	lnbuf := []byte{}
	for i := 0; i < len(partOfSource); i++ {
		if partOfSource[i] == '\n' {
			break
		}

		if partOfSource[i] == '\t' {
			lnbuf = append(lnbuf, ' ')
			continue
		}
		lnbuf = append(lnbuf, partOfSource[i])
	}

	lnstr := string(lnbuf)

	var ofstr string
	if offset <= 0 {
		ofstr = "^"
	} else {
		ofstr = strings.Join(make([]string, offset), " ") + "^"
	}

	_, _ = os.Stderr.Write([]byte(
		fmt.Sprintf(errf, line, col, name, errMsg, lnstr, ofstr)))

	if exit {
		os.Exit(ErrExitCode)
	}
}

// func SemanticErrorHandler(line, col, fileName, errType, errMsg, exit)
type SemanticErrorHandler func(int, int, string, string, string, bool)

func defaultSemanticErrorHandler(
	line, col int, offset int, fileName string,
	errType, errMsg string, exit bool) {

	errf := "%s at (%d : %d) in %s :\n%s\n"

	_, _ = os.Stderr.Write([]byte(
		fmt.Sprintf(errf, errType, line, col, fileName, errMsg)))

	if exit {
		os.Exit(ErrExitCode)
	}
}

func unexpectedError(err error, msg string) {
	if msg != "" {
		msg = "(" + msg + ")" // for output
	}

	_, ferr := fmt.Fprintf(os.Stderr,
		"Unexpected Error: %s %s", err.Error(), msg)

	if ferr != nil {
		panic(ferr)
	}

	os.Exit(1)
}

type Error struct {
	Type    string
	Message string
	Details []string
}

func newError(errType, errMsg string, details []string) *Error {
	return &Error{
		Type:    errType,
		Message: errMsg,
		Details: details,
	}
}
